@page "/settings/security/delete-account"
@inherits MainBase
@using System.Text.Json
@using AliasVault.Client.Utilities
@using AliasVault.Shared.Models.WebApi.Auth
@using AliasVault.Cryptography.Client
@using SecureRemotePassword
@using System.ComponentModel.DataAnnotations
@using Microsoft.Extensions.Localization
@using AliasVault.Client.Resources
@inject HttpClient Http

<LayoutPageTitle>@Localizer["PageTitle"]</LayoutPageTitle>

<div class="grid grid-cols-1 px-4 pt-6 xl:grid-cols-3 xl:gap-4 dark:bg-gray-900">
    <div class="mb-4 col-span-full xl:mb-2">
        <Breadcrumb BreadcrumbItems="BreadcrumbItems"/>
        <H1>@Localizer["PageTitle"]</H1>
    </div>
</div>

<div class="p-4 mb-4 mx-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
    @if (!_showPasswordConfirm)
    {
        <div class="mb-6">
            <MessageWarning Message="@Localizer["PermanentActionWarning"]" />

            <div class="mt-4 mb-6 text-gray-600 dark:text-gray-400">
                <p class="mb-2">@Localizer["PleaseNote"]</p>
                <ul class="list-disc list-inside space-y-2">
                    <li>@Localizer["VaultsDeletedNote"]</li>
                    <li>@Localizer["EmailAliasesOrphanedNote"]</li>
                    <li>@Localizer["AccountCannotBeRecoveredNote"]</li>
                </ul>
            </div>

            <EditForm Model="@_usernameModel" OnSubmit="@ConfirmUsername">
                <div class="mb-4">
                    <label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["ConfirmUsernameLabel"]</label>
                    <InputText id="username" @bind-Value="_usernameModel.Username" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" />
                </div>

                <div class="flex space-x-3">
                    <Button Type="submit" Color="danger">@Localizer["ContinueWithAccountDeletion"]</Button>
                    <Button Type="button" Color="secondary" OnClick="Cancel">@SharedLocalizer["Cancel"]</Button>
                </div>
            </EditForm>
        </div>
    }
    else
    {
        <div class="mb-6">
            <MessageWarning Message="@Localizer["FinalWarning"]" />

            <div class="mt-4 mb-6 text-gray-600 dark:text-gray-400">
                <p class="mb-2">@Localizer["PleaseNote"]</p>
                <ul class="list-disc list-inside space-y-2">
                    <li>@Localizer["DeletionIrreversibleNote"]</li>
                </ul>
            </div>

            <EditForm Model="@_passwordModel" OnValidSubmit="@DeleteAccountConfirmed">
                <DataAnnotationsValidator />
                <ValidationSummary />

                <div class="mb-4">
                    <label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["EnterPasswordLabel"]</label>
                    <InputText id="password" type="password" @bind-Value="_passwordModel.Password" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" />
                </div>

                <div class="flex space-x-3">
                    <Button Type="submit" Color="danger">@Localizer["DeleteMyAccount"]</Button>
                    <Button Type="button" Color="secondary" OnClick="Cancel">@SharedLocalizer["Cancel"]</Button>
                </div>
            </EditForm>
        </div>
    }
</div>

@code {
    /// <summary>
    /// The model for the username confirmation step.
    /// </summary>
    private readonly DeleteAccountUsernameModel _usernameModel = new();

    /// <summary>
    /// The model for the password confirmation step.
    /// </summary>
    private readonly DeleteAccountPasswordModel _passwordModel = new();

    private IStringLocalizer Localizer => LocalizerFactory.Create("Components.Main.Pages.Settings.Security.DeleteAccount", "AliasVault.Client");
    private IStringLocalizer ApiErrorLocalizer => LocalizerFactory.Create("ApiErrors", "AliasVault.Client");

    /// <summary>
    /// Whether to show the password confirmation step.
    /// </summary>
    private bool _showPasswordConfirm;

    /// <summary>
    /// The ephemeral client for SRP.
    /// </summary>
    private SrpEphemeral ClientEphemeral { get; set; } = null!;

    /// <summary>
    /// The session client for SRP.
    /// </summary>
    private SrpSession ClientSession { get; set; } = null!;

    /// <inheritdoc />
    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();

        BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = Localizer["BreadcrumbSecuritySettings"], Url = "/settings/security" });
        BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = Localizer["BreadcrumbDeleteAccount"] });
    }

    /// <summary>
    /// Confirms the username for account deletion.
    /// </summary>
    private async Task ConfirmUsername()
    {
        GlobalNotificationService.ClearMessages();

        if (string.IsNullOrEmpty(_usernameModel.Username))
        {
            GlobalNotificationService.AddErrorMessage(Localizer["UsernameRequired"], true);
            return;
        }

        var username = await GetUsernameAsync();
        var usernameMatches = string.Equals(_usernameModel.Username.Trim(), username.Trim(), StringComparison.OrdinalIgnoreCase);
        if (!usernameMatches)
        {
            GlobalNotificationService.AddErrorMessage(Localizer["UsernameDoesNotMatch"], true);
            return;
        }

        _showPasswordConfirm = true;
        StateHasChanged();
    }

    /// <summary>
    /// Confirms the password via WebApi and if valid deletes the account permanently.
    /// </summary>
    private async Task DeleteAccountConfirmed()
    {
        GlobalLoadingSpinner.Show(Localizer["DeletingAccountMessage"]);
        GlobalNotificationService.ClearMessages();

        try
        {
            // First verify the current password.
            var username = await GetUsernameAsync();
            var result = await Http.PostAsJsonAsync("v1/Auth/delete-account/initiate", new LoginInitiateRequest(username));
            var responseContent = await result.Content.ReadAsStringAsync();

            if (!result.IsSuccessStatusCode)
            {
                foreach (var error in ApiResponseUtility.ParseErrorResponse(responseContent, ApiErrorLocalizer))
                {
                    GlobalNotificationService.AddErrorMessage(error, true);
                }
                return;
            }

            var loginResponse = JsonSerializer.Deserialize<LoginInitiateResponse>(responseContent);
            if (loginResponse == null)
            {
                GlobalNotificationService.AddErrorMessage(Localizer["ErrorProcessingRequest"], true);
                return;
            }

            // Verify password using SRP
            var passwordHash = await Encryption.DeriveKeyFromPasswordAsync(_passwordModel.Password, loginResponse.Salt, loginResponse.EncryptionType, loginResponse.EncryptionSettings);
            var passwordHashString = BitConverter.ToString(passwordHash).Replace("-", string.Empty);

            ClientEphemeral = Srp.GenerateEphemeralClient();
            var privateKey = Srp.DerivePrivateKey(loginResponse.Salt, username, passwordHashString);
            ClientSession = Srp.DeriveSessionClient(
                privateKey,
                ClientEphemeral.Secret,
                loginResponse.ServerEphemeral,
                loginResponse.Salt,
                username);

            // Send final delete request with SRP proof.
            result = await Http.PostAsJsonAsync("v1/Auth/delete-account/confirm", new DeleteAccountRequest(username, ClientEphemeral.Public, ClientSession.Proof));
            responseContent = await result.Content.ReadAsStringAsync();

            if (!result.IsSuccessStatusCode)
            {
                foreach (var error in ApiResponseUtility.ParseErrorResponse(responseContent, ApiErrorLocalizer))
                {
                    GlobalNotificationService.AddErrorMessage(error, true);
                }
                return;
            }

            // Account deleted successfully, redirect to logout page.
            NavigationManager.NavigateTo("/user/logout");
        }
        finally
        {
            GlobalLoadingSpinner.Hide();
        }
    }

    /// <summary>
    /// Cancels the account deletion process.
    /// </summary>
    private void Cancel()
    {
        NavigationManager.NavigateTo("/settings/security");
    }

    /// <summary>
    /// Model for the username confirmation step.
    /// </summary>
    public class DeleteAccountUsernameModel
    {
        /// <summary>
        /// Gets or sets the username.
        /// </summary>
        [Required(ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = nameof(ValidationMessages.UsernameRequired))]
        public string Username { get; set; } = string.Empty;
    }

    /// <summary>
    /// Model for the password confirmation step.
    /// </summary>
    public class DeleteAccountPasswordModel
    {
        /// <summary>
        /// Gets or sets the password.
        /// </summary>
        [Required(ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = nameof(ValidationMessages.PasswordRequired))]
        public string Password { get; set; } = string.Empty;
    }
}
